#include <Arduino.h>

class Matrixled {
public:
    Matrixled(const uint8_t (&pos_pins)[8], const uint8_t (&neg_pins)[3]) {
        for (uint8_t i = 0; i < 8; ++i) {
            this->pos_pins[i] = pos_pins[i];
            if (i < 4) {
                this->neg_pins[i] = neg_pins[i];
            }
        }
    }

    ~Matrixled() {}

    void begin() {
        for (uint8_t i = 0; i < 8; ++i) {
            pinMode(this->pos_pins[i], OUTPUT);
            digitalWrite(this->pos_pins[i], LOW);
            if (i < 4) {
                pinMode(this->neg_pins[i], OUTPUT);
                digitalWrite(this->neg_pins[i], LOW);
            }
        }    
    }

    /**
     * \brief 点亮某一行中的led
     *
     * \param row 点亮某一行，如果输入1则点亮第一行
     * \param which_leds 点亮哪些LED，如果输入0x88（1000 1000），则点亮第一个和第五个LED
     */
    bool lit_row(uint8_t row, uint8_t which_leds) {
        if (row < 1 || row > 8) {
            return false;
        }
        
        // row-1的二进制位对应三个引脚的状态
        uint8_t row_code = row - 1;
        digitalWrite(neg_pins[0], (row_code & 0x01) ? HIGH : LOW);
        digitalWrite(neg_pins[1], (row_code & 0x02) ? HIGH : LOW);
        digitalWrite(neg_pins[2], (row_code & 0x04) ? HIGH : LOW);

        for (int i = 0; i < 8; ++i) {
            digitalWrite(pos_pins[i], (which_leds >> (7 - i)) & 0x01);
        }
        
        return true;
    }

    bool lit_frame(const uint8_t (&which_leds)[8]) {
        for (uint8_t i = 0; i < 8; ++i) {
            if (lit_row(i + 1, which_leds[i])) {
                delay(1);
            } else {
                return false;
            }
        }
        return true;
    }

    bool lit(const uint8_t (&which_leds)[][8], uint32_t size) {
        for (uint32_t i = 0; i < size; ++i) {
            for (uint8_t j = 0; j < 20; ++j) {
                if (lit_frame(which_leds[i])) {
                    delay(1);
                } else {
                    return false;
                }       
            }
        }
        return true;
    }

private:
    uint8_t pos_pins[8];
    uint8_t neg_pins[3];

};

const uint8_t matrixled_pos_pins[8] = {PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8};
const uint8_t matrixled_neg_pins[3] = {PA13, PA14, PA15};

Matrixled maxtrixled(matrixled_pos_pins, matrixled_neg_pins);

const uint8_t animation[][8] = {
    {0x00, 0x0E, 0x1B, 0x7F, 0x7F, 0x1B, 0x0E, 0x00},
    {0x00, 0x04, 0x0C, 0x18, 0x7F, 0x7F, 0x1B, 0x0E},
    {0x00, 0x08, 0x0C, 0x05, 0x7F, 0x7F, 0x1E, 0x0C},
    {0xC0, 0x00, 0x41, 0x22, 0x1A, 0x7C, 0x7D, 0x1A},
    {0x00, 0x60, 0x61, 0x12, 0x0A, 0x7E, 0x7F, 0x08},
    {0x00, 0x06, 0x0E, 0x08, 0x0B, 0x3E, 0x3E, 0x0B},
    {0x00, 0x03, 0x0B, 0x08, 0x0B, 0x3E, 0x3E, 0x0B},
    {0x00, 0x06, 0x0E, 0x08, 0x09, 0x3F, 0x3E, 0x0B},
    {0x00, 0x0E, 0x13, 0x7E, 0x7E, 0x1F, 0x0E, 0x00},
    {0x08, 0x13, 0x7E, 0x7E, 0x12, 0x1D, 0x0C, 0x00},
    {0x09, 0x12, 0x7E, 0x7F, 0x10, 0x13, 0x03, 0x00},
    {0x09, 0x12, 0x7E, 0x7F, 0x10, 0x1C, 0x0C, 0x00},
    {0x00, 0x0C, 0x15, 0x7E, 0x7E, 0x17, 0x0E, 0x00},
    {0x00, 0x30, 0x38, 0x0D, 0x7E, 0x7F, 0x1D, 0x08},
    {0xC0, 0xC0, 0x30, 0x1B, 0x7C, 0x7F, 0x08, 0x00},
    {0x00, 0x00, 0x37, 0xF8, 0xFA, 0x34, 0x00, 0x00},
    {0x00, 0x00, 0x1B, 0x7C, 0x7C, 0x1A, 0x01, 0x00},
    {0x00, 0x00, 0x09, 0x1E, 0x7C, 0x7F, 0x18, 0x00},
    {0x00, 0x00, 0x1B, 0x7C, 0x7C, 0x1B, 0x00, 0x00},
    {0x00, 0x00, 0x09, 0x1E, 0x7C, 0x7F, 0x18, 0x00},
    {0x00, 0x00, 0x1B, 0x7C, 0x7C, 0x1B, 0x00, 0x00},
    {0x08, 0x10, 0x16, 0x7C, 0x7F, 0x10, 0x08, 0x00},
    {0x00, 0x10, 0x13, 0x7C, 0x7E, 0x18, 0x00, 0x00},
    {0x00, 0x08, 0x13, 0x7C, 0x7F, 0x10, 0x10, 0x00},
    {0x00, 0x08, 0x12, 0xFC, 0xFD, 0x3A, 0x00, 0x00},
    {0x00, 0x08, 0x12, 0xFC, 0xFC, 0x22, 0x10, 0x00},
    {0x00, 0x00, 0x61, 0x12, 0x7C, 0x7F, 0x10, 0x60},
    {0x00, 0x00, 0x20, 0x11, 0x12, 0x7C, 0x7E, 0x19},
    {0x00, 0x00, 0x00, 0x31, 0x0A, 0x7C, 0x7E, 0x0D},
    {0x00, 0x00, 0x20, 0x11, 0x12, 0x7C, 0x7E, 0x19},
    {0x00, 0x00, 0x00, 0x31, 0x0A, 0x7C, 0x7E, 0x0D},
    {0x00, 0x00, 0x20, 0x11, 0x12, 0x7C, 0x7E, 0x19},
    {0x00, 0x00, 0x00, 0x31, 0x0A, 0x7C, 0x7E, 0x0D},
    {0x00, 0x00, 0x20, 0x11, 0x12, 0x7C, 0x7E, 0x19},
    {0x00, 0x00, 0x00, 0x31, 0x0A, 0x7C, 0x7E, 0x0D}
};



void setup() {
    maxtrixled.begin();
}

void loop() {
    maxtrixled.lit(animation, sizeof(animation) / sizeof(animation[0]));
}
